/*
    !!! version-1 文件版
    @note 根据题目的list文件，加载所有的题目信息到内存
    @brief 主要和数据进行交互， 对外提供访问数据的接口
*/

#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <fstream>
#include <cassert>
#include "comm/log.hpp"
#include "comm/util.hpp"

namespace ns_model
{
    using namespace ns_log;
    using namespace ns_util;
    struct Question
    {
        std::string number; // 题目的编号，唯一
        std::string title;  // 题目的标题
        std::string star;   // 难度：简单，中等，困难
        int cpu_limit;      // 题目的时间要求（s）
        int mem_limit;      // 题目的空间要求 （kb）
        std::string desc;   // 题目的描述
        std::string header;
        std::string tail; // 题目测试用例，需要和header拼接，形成完整的代码
    };
    const std::string questionList(("/home/zdl/zdl/load-balanced-online-oj-testing-project/oj_server/questions/question.list"));
    const std::string questionPath(("/home/zdl/zdl/load-balanced-online-oj-testing-project/oj_server/questions"));
    class Model
    {
    private:
        // 题目：题目的细节
        std::unordered_map<std::string, Question> questions;
    public:
        Model()
        {
            assert(loadQuestionList(questionList));
        }
        bool loadQuestionList(const std::string &question_list)
        {
            //? 加载配置文件：question/question.list + 题目编号文件
            std::fstream in(question_list);
            if (!in.is_open())
            {
                LOG(FATAL) << "加载题库失败,请检查是否存在题库文件" << std::endl;
                return false;
            }

            std::string line;
            while (std::getline(in, line))
            {
                std::vector<std::string> tokens;
                StringUtil::splitString(line, &tokens, " ");
                // 1 判断回文数 简单 1 30000
                if (tokens.size() != 5)
                {
                    LOG(WARNING) << "加载部分题目失败，请检查题目的文件格式" << std::endl;
                    continue;
                }
                Question q;
                q.number = tokens[0];
                q.title = tokens[1];
                q.star = tokens[2];
                q.cpu_limit = std::stoi(tokens[3]);
                q.mem_limit = std::stoi(tokens[4]);

                std::string path = questionPath;
                path += "/";
                path += q.number;
                FileUtil::readFile(path + "/desc.txt", &(q.desc), true);
                FileUtil::readFile(path + "/header.cc", &(q.header), true);
                FileUtil::readFile(path + "/tail.cc", &(q.tail), true);
                questions.emplace(q.number, q);
            }
            LOG(INFO) << "加载题库成功" << std::endl;
            in.close();
            return true;
        }
        bool getAllQuestion(std::vector<Question> *out)
        {
            if (!questions.size())
            {
                LOG(ERROR) << "用户获取题目失败" << std::endl;

                return false;
            }
            for (auto &x : questions)
                out->emplace_back(x.second);
            return true;
        }
        bool getOneQuestion(const std::string &number, Question *out)
        {
            if (questions.count(number))
            {
                *out = questions[number];
                return true;
            }
            LOG(ERROR) << "用户获取题目失败, 题目编号为 : " << number << std::endl;
            return false;
        }
        ~Model()
        {
        }
    };
}